#ifndef __test_kenny_kfjiweur89u83r33e3e__
#define __test_kenny_kfjiweur89u83r33e3e__

#include <list>
#include <tuple>
#include <string>
#include <memory>

#include <hude/base/base_type.hpp>
#include <hude/utils/clipp.hpp>
#include <hude/base/log.hpp>

namespace test_a93i
{
    //--------------------------------------------------------------------------------
    struct case_t
    {
        virtual ~case_t() {}

        virtual bool init() { return true; }
        virtual bool deinit() { return true; }
        virtual bool run() = 0;
    };

    //--------------------------------------------------------------------------------
    struct test_t
    {
        typedef std::shared_ptr< case_t > ptr_case_t;
        typedef std::tuple< std::string, ptr_case_t, bool > item_t;
        typedef std::list< item_t > queue_t;

        queue_t queue_;

        void init();
        int run( int, const char* [] );

        static test_t& obj();
    };

    //--------------------------------------------------------------------------------
    template< typename _case >
    struct _regsitor_t
    {
        _regsitor_t( const char* name, bool enable )
        {
            auto& test = test_t::obj();

            test.queue_.push_back( test_t::item_t{ std::string{ name }, test_t::ptr_case_t{ new _case }, enable } );
        }
    };

    #define TEST_CASE_ADD( casename, classname, enable )   hude::test::_regsitor_t< classname > _regsitor_##classname{ casename, enable }

    //--------------------------------------------------------------------------------
    inline int test_t::run( int argc, const char* argv[] )
    {
        int result = 0;

        for( auto item : queue_ )
        {
            const auto& name = std::get< 0 >( item );
            auto ptr = std::get< 1 >( item );
            auto enable = std::get< 2 >( item );

            if( argc > 1 )
            {
                if( strcmp( argv[1], "all" ) != 0 && name != argv[1] )
                    continue;
            } else {
                if( ! enable ) continue;
            }

            std::string bd;
            bd.resize( ( 80 - name.length() ) / 2, '-' );

            tlog_inf( "<test>", " " );
            tlog_inf( "<test>", "%s--- init  case: %s ---%s", bd.c_str(), name.c_str(), bd.c_str() );
            tlog_inf( "<test>", " " );

            ptr->init();
            tlog_inf( "<test>", "# case init done." );

            tlog_inf( "<test>", " " );
            tlog_inf( "<test>", "%s--- start case: %s ---%s", bd.c_str(), name.c_str(), bd.c_str() );
            tlog_inf( "<test>", " " );

            auto ret = ptr->run();

            if( ret )
            {
                tlog_nte( "<test>", " " );
                tlog_nte( "<test>", "%s finish case: %s PASS %s", bd.c_str(), name.c_str(), bd.c_str() );
                tlog_nte( "<test>", " " );
            } else {
                tlog_err( "<test>", "%s finish case: %s FAIL %s", bd.c_str(), name.c_str(), bd.c_str() );
                result -= 1;
            }
        }

        return result;
    }

    //--------------------------------------------------------------------------------
    inline test_t& test_t::obj()
    {
        static test_t test;

        return test;
    }
} // namespace test_a93i

namespace hude
{
    namespace test = ::test_a93i;
} // namespace hude

#endif // __test_kenny_kfjiweur89u83r33e3e__


